/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.wire.wirings
{
	import org.etherframework.core.IBridge;
	import org.etherframework.reflection.Accessor;
	import org.etherframework.reflection.Metadata;
	import org.etherframework.reflection.MetadataMember;
	import org.etherframework.reflection.Variable;
	import org.etherframework.wire.WiringData;

	public final class Hook implements IWiring, IInjection
	{
		public var member:Object;
		
		public function wire(name:String, target:Object, item:Object, data:WiringData):Boolean
		{
			if (!((target is Class) || (item.isStatic) || (item is Variable) || (item is Accessor)))
				return false;
			
			var member:MetadataMember = item as MetadataMember;
			var metadatas:Array;
			var metadatasLen:int;
			var metadata:Metadata;
			var facade:HookFacade;
			
			metadatas = member.metadata;
			metadatasLen = metadatas.length;
			this.member = (member.uri) ? 
				new QName(new Namespace(member.uri), member.name) : member.name;
			
			try {
				for (var i:int = 0; i < metadatasLen; ++i)
				{
					metadata = metadatas[i];
					
					if (metadata.name == name)
					{
						facade = new HookFacade(data.bridge.addWire, data.bridge.removeWire);
						
						if (!target[this.member])
						{
							target[this.member] = facade;
							return true;
						}
						
						break;
					}
				}
			} catch (e:Error) {}
			
			return false;
		}
		
		public function unwire(target:Object):Boolean
		{
			try {
				if (target[member])
				{
					target[member] = null;
					return true;
				}
			} catch (e:*) {}
			
			return false;
		}
		
		public function inject(name:String, target:Object, data:WiringData):Boolean
		{
			if (!(target is Class))
				return false;
			
			try {
				if (!target[member])
				{
					target[member] = new HookFacade(data.bridge.addWire, data.bridge.removeWire);
					return true;
				}
			} catch (e:*) {}
			
			return false;
		}
			
	}
}


final class HookFacade
{
	private var wireClosure:Function;
	
	private var unwireClosure:Function;
	
	public function HookFacade(wireClosure:Function, unwireClosure:Function)
	{
		this.wireClosure = wireClosure;
		this.unwireClosure = unwireClosure;
	}
	
	public function wire(value:Object):void
	{
		if (!value)
			return;
		
		wireClosure(value);
	}
	
	public function unwire(value:Object):void
	{
		if (!value)
			return;
		
		unwireClosure(value);
	}
}